/**
 * Copyright &copy; 2012-2014 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.vidmt.api.modules.sys.shiro;

import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Sets;
import com.thinkgem.jeesite.modules.sys.entity.Menu;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils;
import com.vidmt.api.modules.sys.Acc;
import com.vidmt.api.modules.sys.Enums.AccType;
import com.vidmt.api.modules.sys.entity.User;
import com.vidmt.api.modules.sys.service.UserService;

/**
 * 系统安全认证实现类
 * 
 * @author ThinkGem
 * @version 2014-7-5
 */
@Service
// @DependsOn({"userDao","roleDao","menuDao"})
public class MyApiRealm extends AuthorizingRealm {

	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private UserService userService;
	// @Autowired
	// private SystemService systemService;

	@Autowired
	private CachingSessionDAO sessionDao;

	@Override
	public boolean supports(AuthenticationToken token) {
		return token != null && MyApiToken.class.isAssignableFrom(token.getClass());
	}

	public MyApiRealm() {
		super(new MyCredentialMather());
	}

	/**
	 * 认证回调函数, 登录时调用
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {
		MyApiToken token = (MyApiToken) authcToken;
		Acc acc = (Acc) token.getPrincipal();
		User user = null;
		if (acc.type() == AccType.uid) {
			user = userService.load(Long.valueOf(acc.value()));
		} else {
			user = userService.findByAcc(acc);
		}

		String pwd = userService.getPwd(user.getId());
		MyPrincipal principal = new MyPrincipal(user);
		principal.setOs(token.getOs());
		principal.setVer(token.getVer());
		principal.setChannel(token.getChannel());
		return new SimpleAuthenticationInfo(principal, pwd, getName());
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		MyPrincipal principal = (MyPrincipal) getAvailablePrincipal(principals);
		// API不允许用户同时多个地方登录
		Session sess = UserUtils.getSession();
		if (principal != null && sess != null) {
			// 找出已经登录的用户
			PrincipalCollection pc = (PrincipalCollection) sess
					.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
			MyPrincipal tmpPrincipal = pc != null ? (MyPrincipal) pc.getPrimaryPrincipal() : null;
			boolean sameUser = tmpPrincipal != null && principal.getUser().equals(tmpPrincipal.getUser());

			Set<Session> sessions = Sets.newHashSet();
			for (Session tmpsess : sessionDao.getActiveSessions()) {
				if (sameUser && !sess.getId().equals(tmpsess.getId())) {
					sessions.add(tmpsess);
				}
			}
			// 如果有已登录用户，则踢出已在线用户
			if (sessions.size() > 0) {
				if (UserUtils.getSubject().isAuthenticated()) {
					for (Session session : sessions) {
						sessionDao.delete(session);
					}
				}
				// 记住我进来的，并且当前用户已登录，则退出当前用户提示信息。
				else {
					UserUtils.getSubject().logout();
					throw new AuthenticationException("msg:账号已在其它地方登录，请重新登录。");
				}
			}
		}

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		List<Menu> list = UserUtils.getAllMenuList();
		for (Menu menu : list) {
			if (StringUtils.isNotBlank(menu.getPermission())) {
				// 添加基于Permission的权限信息
				for (String permission : StringUtils.split(menu.getPermission(), ",")) {
					info.addStringPermission(permission);
				}
			}
		}
		// 添加用户权限
		info.addStringPermission("user");
		return info;
	}
}
